package com.tidu.secret.service;

import com.tidu.secret.util.AESUtil;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 文档安全处理服务
 */
@Service
public class DocumentSecurityService {
    
    /**
     * 处理文档中的敏感内容
     */
    public byte[] processDocument(MultipartFile file, List<String> sensitiveWords) throws Exception {
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        if (fileName.toLowerCase().endsWith(".docx")) {
            return processDocxDocument(file, sensitiveWords);
        } else if (fileName.toLowerCase().endsWith(".doc")) {
            return processDocDocument(file, sensitiveWords);
        } else {
            throw new IllegalArgumentException("不支持的文件格式，仅支持.doc和.docx文件");
        }
    }
    
    /**
     * 处理.docx文档
     */
    private byte[] processDocxDocument(MultipartFile file, List<String> sensitiveWords) throws Exception {
        try (XWPFDocument document = new XWPFDocument(file.getInputStream())) {
            
            // 遍历所有段落
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            if (paragraphs != null) {
                for (int i = 0; i < paragraphs.size(); i++) {
                    try {
                        XWPFParagraph paragraph = paragraphs.get(i);
                        if (paragraph != null) {
                            processParagraph(paragraph, sensitiveWords);
                        }
                    } catch (Exception e) {
                        System.err.println("处理第 " + (i + 1) + " 个段落时出错: " + e.getMessage());
                        // 继续处理下一个段落，不中断整个处理过程
                    }
                }
            }
            
            // 将处理后的文档转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.write(outputStream);
            return outputStream.toByteArray();
        }
    }
    
    /**
     * 处理.doc文档
     */
    private byte[] processDocDocument(MultipartFile file, List<String> sensitiveWords) throws Exception {
        try (HWPFDocument document = new HWPFDocument(file.getInputStream())) {
            
            Range range = document.getRange();
            String originalText = range.text();
            
            if (originalText == null || originalText.trim().isEmpty()) {
                // 如果文档为空，直接返回原文档
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                document.write(outputStream);
                return outputStream.toByteArray();
            }
            
            // 替换敏感词
            String processedText = replaceSensitiveWords(originalText, sensitiveWords);
            
            // 只有当文本发生变化时才进行替换
            if (!originalText.equals(processedText)) {
                try {
                    // 使用更安全的替换方法
                    range.replaceText(originalText, processedText);
                } catch (Exception e) {
                    System.err.println("使用replaceText失败，尝试删除和插入方法: " + e.getMessage());
                    try {
                        // 备用方法：先删除再插入
                        int startOffset = range.getStartOffset();
                        int endOffset = range.getEndOffset();
                        
                        // 确保偏移量有效
                        if (startOffset >= 0 && endOffset > startOffset && endOffset <= document.getRange().getEndOffset()) {
                            range.delete();
                            // 修复API调用：insertAfter方法需要的是字符串参数
                            Range newRange = document.getRange().insertAfter(processedText);
                        } else {
                            System.err.println("无效的偏移量，跳过文档处理");
                        }
                    } catch (Exception e2) {
                        System.err.println("备用方法也失败，返回原文档: " + e2.getMessage());
                        // 如果所有方法都失败，返回原文档
                    }
                }
            }
            
            // 将处理后的文档转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.write(outputStream);
            return outputStream.toByteArray();
        }
    }
    
    /**
     * 处理段落中的敏感词
     */
    private void processParagraph(XWPFParagraph paragraph, List<String> sensitiveWords) throws Exception {
        if (paragraph == null) {
            return;
        }
        
        // 使用段落的getText()方法获取完整文本，这样更安全
        String originalText = paragraph.getText();
        if (originalText == null || originalText.trim().isEmpty()) {
            return;
        }
        
        String processedText = replaceSensitiveWords(originalText, sensitiveWords);
        
        // 如果文本发生了变化，更新段落
        if (!originalText.equals(processedText)) {
            try {
                // 保存原有的格式信息
                List<XWPFRun> originalRuns = new ArrayList<>(paragraph.getRuns());
                boolean hasFormatting = originalRuns.size() > 1;
                
                if (hasFormatting && originalRuns.size() > 0) {
                    // 如果有多个runs（可能包含格式），尝试保持第一个run的格式
                    XWPFRun firstRun = originalRuns.get(0);
                    
                    // 清除所有runs
                    while (paragraph.getRuns().size() > 0) {
                        paragraph.removeRun(0);
                    }
                    
                    // 创建新的run并复制格式
                    XWPFRun newRun = paragraph.createRun();
                    if (newRun != null && firstRun != null) {
                        // 复制基本格式
                        newRun.setBold(firstRun.isBold());
                        newRun.setItalic(firstRun.isItalic());
                        newRun.setUnderline(firstRun.getUnderline());
                        if (firstRun.getFontFamily() != null) {
                            newRun.setFontFamily(firstRun.getFontFamily());
                        }
                        if (firstRun.getFontSize() > 0) {
                            newRun.setFontSize(firstRun.getFontSize());
                        }
                        newRun.setText(processedText, 0);
                    }
                } else {
                    // 简单情况：只有一个run或没有特殊格式
                    while (paragraph.getRuns().size() > 0) {
                        paragraph.removeRun(0);
                    }
                    
                    XWPFRun newRun = paragraph.createRun();
                    if (newRun != null) {
                        newRun.setText(processedText, 0);
                    }
                }
            } catch (Exception e) {
                System.err.println("处理段落时出现错误: " + e.getMessage());
                try {
                    // 最后的备用方法：尝试直接设置第一个run的文本
                    List<XWPFRun> runs = paragraph.getRuns();
                    if (runs.size() > 0) {
                        XWPFRun firstRun = runs.get(0);
                        firstRun.setText(processedText, 0);
                        
                        // 清除其他runs
                        for (int i = runs.size() - 1; i > 0; i--) {
                            paragraph.removeRun(i);
                        }
                    }
                } catch (Exception e2) {
                    System.err.println("备用方法也失败，跳过此段落: " + e2.getMessage());
                    // 记录错误但不抛出异常，继续处理其他段落
                }
            }
        }
    }
    
    /**
     * 替换文本中的敏感词
     */
    private String replaceSensitiveWords(String text, List<String> sensitiveWords) throws Exception {
        if (text == null || text.isEmpty()) {
            return text;
        }
        
        if (sensitiveWords == null || sensitiveWords.isEmpty()) {
            return text;
        }
        
        String result = text;
        
        for (String sensitiveWord : sensitiveWords) {
            if (sensitiveWord != null && !sensitiveWord.trim().isEmpty()) {
                try {
                    // 使用正则表达式进行大小写不敏感的匹配
                    Pattern pattern = Pattern.compile(Pattern.quote(sensitiveWord.trim()), Pattern.CASE_INSENSITIVE);
                    Matcher matcher = pattern.matcher(result);
                    
                    StringBuffer sb = new StringBuffer();
                    while (matcher.find()) {
                        String foundWord = matcher.group();
                        try {
                            String encrypted = AESUtil.encrypt(foundWord);
                            String formatted = AESUtil.formatEncryptedText(encrypted);
                            matcher.appendReplacement(sb, Matcher.quoteReplacement(formatted));
                        } catch (Exception e) {
                            System.err.println("加密敏感词失败: " + foundWord + ", 错误: " + e.getMessage());
                            // 如果加密失败，使用简单的替换
                            matcher.appendReplacement(sb, Matcher.quoteReplacement("[已加密:" + foundWord + "]"));
                        }
                    }
                    matcher.appendTail(sb);
                    result = sb.toString();
                } catch (Exception e) {
                    System.err.println("处理敏感词时出错: " + sensitiveWord + ", 错误: " + e.getMessage());
                    // 继续处理下一个敏感词
                }
            }
        }
        
        return result;
    }
    
    /**
     * 解密文档中的加密内容
     */
    public byte[] decryptDocument(MultipartFile file) throws Exception {
        String fileName = file.getOriginalFilename();
        
        if (fileName == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        if (fileName.toLowerCase().endsWith(".docx")) {
            return decryptDocxDocument(file);
        } else if (fileName.toLowerCase().endsWith(".doc")) {
            return decryptDocDocument(file);
        } else {
            throw new IllegalArgumentException("不支持的文件格式，仅支持.doc和.docx文件");
        }
    }
    
    /**
     * 解密.docx文档
     */
    private byte[] decryptDocxDocument(MultipartFile file) throws Exception {
        try (XWPFDocument document = new XWPFDocument(file.getInputStream())) {
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            
            for (int i = 0; i < paragraphs.size(); i++) {
                XWPFParagraph paragraph = paragraphs.get(i);
                if (paragraph != null) {
                    try {
                        decryptParagraph(paragraph);
                    } catch (Exception e) {
                        System.err.println("解密第" + (i + 1) + "段时出错: " + e.getMessage());
                        // 继续处理其他段落
                    }
                }
            }
            
            // 将处理后的文档转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.write(outputStream);
            return outputStream.toByteArray();
        }
    }
    
    /**
     * 解密.doc文档
     */
    private byte[] decryptDocDocument(MultipartFile file) throws Exception {
        try (HWPFDocument document = new HWPFDocument(file.getInputStream())) {
            Range range = document.getRange();
            String originalText = range.text();
            
            if (originalText == null || originalText.trim().isEmpty()) {
                // 如果文档为空，返回原文档
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                document.write(outputStream);
                return outputStream.toByteArray();
            }
            
            String decryptedText = decryptText(originalText);
            
            // 如果文本发生了变化，更新文档
            if (!originalText.equals(decryptedText)) {
                try {
                    // 使用replaceText方法进行安全替换
                    range.replaceText(originalText, decryptedText);
                } catch (Exception e) {
                    System.err.println("使用replaceText失败，尝试备用方法: " + e.getMessage());
                    try {
                        // 备用方法：先删除再插入
                        int startOffset = range.getStartOffset();
                        int endOffset = range.getEndOffset();
                        
                        // 确保偏移量有效
                        if (startOffset >= 0 && endOffset > startOffset && endOffset <= document.getRange().getEndOffset()) {
                            range.delete();
                            // 修复API调用：insertAfter方法需要的是字符串参数
                            Range newRange = document.getRange().insertAfter(decryptedText);
                        } else {
                            System.err.println("无效的偏移量，跳过文档处理");
                        }
                    } catch (Exception e2) {
                        System.err.println("备用方法也失败，返回原文档: " + e2.getMessage());
                        // 如果所有方法都失败，返回原文档
                    }
                }
            }
            
            // 将处理后的文档转换为字节数组
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            document.write(outputStream);
            return outputStream.toByteArray();
        }
    }
    
    /**
     * 解密段落中的加密内容
     */
    private void decryptParagraph(XWPFParagraph paragraph) throws Exception {
        if (paragraph == null) {
            return;
        }
        
        // 使用段落的getText()方法获取完整文本，这样更安全
        String originalText = paragraph.getText();
        if (originalText == null || originalText.trim().isEmpty()) {
            return;
        }
        
        String decryptedText = decryptText(originalText);
        
        // 如果文本发生了变化，更新段落
        if (!originalText.equals(decryptedText)) {
            try {
                // 保存原有的格式信息
                List<XWPFRun> originalRuns = new ArrayList<>(paragraph.getRuns());
                boolean hasFormatting = originalRuns.size() > 1;
                
                if (hasFormatting && originalRuns.size() > 0) {
                    // 如果有多个runs（可能包含格式），尝试保持第一个run的格式
                    XWPFRun firstRun = originalRuns.get(0);
                    
                    // 清除所有runs
                    while (paragraph.getRuns().size() > 0) {
                        paragraph.removeRun(0);
                    }
                    
                    // 创建新的run并复制格式
                    XWPFRun newRun = paragraph.createRun();
                    if (newRun != null && firstRun != null) {
                        // 复制基本格式
                        newRun.setBold(firstRun.isBold());
                        newRun.setItalic(firstRun.isItalic());
                        newRun.setUnderline(firstRun.getUnderline());
                        if (firstRun.getFontFamily() != null) {
                            newRun.setFontFamily(firstRun.getFontFamily());
                        }
                        if (firstRun.getFontSize() > 0) {
                            newRun.setFontSize(firstRun.getFontSize());
                        }
                        newRun.setText(decryptedText, 0);
                    }
                } else {
                    // 简单情况：只有一个run或没有特殊格式
                    while (paragraph.getRuns().size() > 0) {
                        paragraph.removeRun(0);
                    }
                    
                    XWPFRun newRun = paragraph.createRun();
                    if (newRun != null) {
                        newRun.setText(decryptedText, 0);
                    }
                }
            } catch (Exception e) {
                System.err.println("解密段落时出现错误: " + e.getMessage());
                try {
                    // 最后的备用方法：尝试直接设置第一个run的文本
                    List<XWPFRun> runs = paragraph.getRuns();
                    if (runs.size() > 0) {
                        XWPFRun firstRun = runs.get(0);
                        firstRun.setText(decryptedText, 0);
                        
                        // 清除其他runs
                        for (int i = runs.size() - 1; i > 0; i--) {
                            paragraph.removeRun(i);
                        }
                    }
                } catch (Exception e2) {
                    System.err.println("备用方法也失败，跳过此段落: " + e2.getMessage());
                    // 记录错误但不抛出异常，继续处理其他段落
                }
            }
        }
    }
    
    /**
     * 解密文本中的加密内容
     */
    private String decryptText(String text) throws Exception {
        if (text == null || text.isEmpty()) {
            return text;
        }
        
        String result = text;
        
        // 查找所有AES加密的内容 [AES:xxxxx]
        Pattern aesPattern = Pattern.compile("\\[AES:([^\\]]+)\\]");
        Matcher aesMatcher = aesPattern.matcher(result);
        
        StringBuffer sb = new StringBuffer();
        while (aesMatcher.find()) {
            String encryptedContent = aesMatcher.group(1);
            try {
                String decrypted = AESUtil.decrypt(encryptedContent);
                aesMatcher.appendReplacement(sb, Matcher.quoteReplacement(decrypted));
            } catch (Exception e) {
                System.err.println("解密AES内容失败: " + encryptedContent + ", 错误: " + e.getMessage());
                // 如果解密失败，保持原样
                aesMatcher.appendReplacement(sb, Matcher.quoteReplacement(aesMatcher.group()));
            }
        }
        aesMatcher.appendTail(sb);
        result = sb.toString();
        
        // 查找所有简单加密的内容 [已加密:xxxxx]
        Pattern simplePattern = Pattern.compile("\\[已加密:([^\\]]+)\\]");
        Matcher simpleMatcher = simplePattern.matcher(result);
        
        StringBuffer sb2 = new StringBuffer();
        while (simpleMatcher.find()) {
            String originalContent = simpleMatcher.group(1);
            // 直接还原原始内容
            simpleMatcher.appendReplacement(sb2, Matcher.quoteReplacement(originalContent));
        }
        simpleMatcher.appendTail(sb2);
        result = sb2.toString();
        
        return result;
    }
    
    /**
     * 识别文档中的敏感内容位置
     */
    public List<SensitiveContentInfo> identifySensitiveContent(MultipartFile file, List<String> sensitiveWords) throws Exception {
        List<SensitiveContentInfo> results = new ArrayList<>();
        String fileName = file.getOriginalFilename();
        
        if (fileName == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        if (fileName.toLowerCase().endsWith(".docx")) {
            return identifyInDocx(file, sensitiveWords);
        } else if (fileName.toLowerCase().endsWith(".doc")) {
            return identifyInDoc(file, sensitiveWords);
        } else {
            throw new IllegalArgumentException("不支持的文件格式，仅支持.doc和.docx文件");
        }
    }
    
    /**
     * 在.docx文档中识别敏感内容
     */
    private List<SensitiveContentInfo> identifyInDocx(MultipartFile file, List<String> sensitiveWords) throws Exception {
        List<SensitiveContentInfo> results = new ArrayList<>();
        
        try (XWPFDocument document = new XWPFDocument(file.getInputStream())) {
            List<XWPFParagraph> paragraphs = document.getParagraphs();
            
            for (int i = 0; i < paragraphs.size(); i++) {
                XWPFParagraph paragraph = paragraphs.get(i);
                String text = paragraph.getText();
                
                if (text != null) {
                    for (String sensitiveWord : sensitiveWords) {
                        if (sensitiveWord != null && !sensitiveWord.trim().isEmpty()) {
                            Pattern pattern = Pattern.compile(Pattern.quote(sensitiveWord), Pattern.CASE_INSENSITIVE);
                            Matcher matcher = pattern.matcher(text);
                            
                            while (matcher.find()) {
                                SensitiveContentInfo info = new SensitiveContentInfo();
                                info.setSensitiveWord(sensitiveWord);
                                info.setFoundText(matcher.group());
                                info.setParagraphIndex(i + 1);
                                info.setStartPosition(matcher.start());
                                info.setEndPosition(matcher.end());
                                info.setContext(getContext(text, matcher.start(), matcher.end()));
                                results.add(info);
                            }
                        }
                    }
                }
            }
        }
        
        return results;
    }
    
    /**
     * 在.doc文档中识别敏感内容
     */
    private List<SensitiveContentInfo> identifyInDoc(MultipartFile file, List<String> sensitiveWords) throws Exception {
        List<SensitiveContentInfo> results = new ArrayList<>();
        
        try (HWPFDocument document = new HWPFDocument(file.getInputStream())) {
            Range range = document.getRange();
            String text = range.text();
            
            for (String sensitiveWord : sensitiveWords) {
                if (sensitiveWord != null && !sensitiveWord.trim().isEmpty()) {
                    Pattern pattern = Pattern.compile(Pattern.quote(sensitiveWord), Pattern.CASE_INSENSITIVE);
                    Matcher matcher = pattern.matcher(text);
                    
                    while (matcher.find()) {
                        SensitiveContentInfo info = new SensitiveContentInfo();
                        info.setSensitiveWord(sensitiveWord);
                        info.setFoundText(matcher.group());
                        info.setStartPosition(matcher.start());
                        info.setEndPosition(matcher.end());
                        info.setContext(getContext(text, matcher.start(), matcher.end()));
                        results.add(info);
                    }
                }
            }
        }
        
        return results;
    }
    
    /**
     * 获取敏感词的上下文
     */
    private String getContext(String text, int start, int end) {
        int contextStart = Math.max(0, start - 20);
        int contextEnd = Math.min(text.length(), end + 20);
        return text.substring(contextStart, contextEnd);
    }
    
    /**
     * 敏感内容信息类
     */
    public static class SensitiveContentInfo {
        private String sensitiveWord;
        private String foundText;
        private int paragraphIndex;
        private int startPosition;
        private int endPosition;
        private String context;
        
        // Getters and Setters
        public String getSensitiveWord() { return sensitiveWord; }
        public void setSensitiveWord(String sensitiveWord) { this.sensitiveWord = sensitiveWord; }
        
        public String getFoundText() { return foundText; }
        public void setFoundText(String foundText) { this.foundText = foundText; }
        
        public int getParagraphIndex() { return paragraphIndex; }
        public void setParagraphIndex(int paragraphIndex) { this.paragraphIndex = paragraphIndex; }
        
        public int getStartPosition() { return startPosition; }
        public void setStartPosition(int startPosition) { this.startPosition = startPosition; }
        
        public int getEndPosition() { return endPosition; }
        public void setEndPosition(int endPosition) { this.endPosition = endPosition; }
        
        public String getContext() { return context; }
        public void setContext(String context) { this.context = context; }
    }
}